package wh.coach.domain.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.jetbrains.annotations.Nullable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import wh.coach.domain.User2;
import wh.coach.domain.error.OptimisticLockException;
import wh.coach.domain.service.User2Service;
import wh.coach.domain.store.ObjectWrapper;
import wh.coach.domain.store.RedisObjectStore;
import wh.coach.reposity.mapper.User2Mapper;

/**
 * @Author xhw
 * @Date 2023/9/26
 * @Version 1.0
 */
@Component
class User2ServiceImpl implements User2Service {
    private final User2Mapper user2Mapper;
    private final RedisObjectStore<User2> cacheStore;

    User2ServiceImpl(User2Mapper user2Mapper, StringRedisTemplate stringRedisTemplate) {
        this.user2Mapper = user2Mapper;
        this.cacheStore = new RedisObjectStore<>(stringRedisTemplate, User2.class);
    }

    @Override
    public void addUser(User2 user) {
        //自动修改 lastChanged 时间
        user.setLastChanged(LocalDateTime.now());

        user2Mapper.add(user);
    }

    @Override
    public void deleteUserById(Long userId) {
        user2Mapper.deleteById(userId);
        this.cacheStore.remove(genKey(userId));
    }

    @Override
    public List<User2> findUsersBySearchName(String searchName) {
        return user2Mapper.findBySearchName(searchName);
    }

    @Override
    public List<User2> getAllUsers() {
        return user2Mapper.getAllUsers();
    }

    @Override
    public User2 getUserById(Long userId) {
        final String redisKey = genKey(userId);
        final var userWrapper = this.cacheStore.getObject(redisKey);

        return extractUserOrLoadFromDB(userWrapper, userId, redisKey);
    }

    @Override
    public List<User2> getUsersByIds(final Collection<Long> userIds) {
        //构造缓存键集合
        final List<Long> userIdList = new ArrayList<>(userIds);
        final List<String> redisKeys = userIdList.stream().map(this::genKey).toList();
        final List<ObjectWrapper<User2>> objectWrappers = this.cacheStore.getObjects(redisKeys);

        final List<User2> users = new ArrayList<>();

        for (int i = 0; i < userIdList.size(); i++) {
            final Long userId = userIdList.get(i);
            final String redisKey = redisKeys.get(i);
            final ObjectWrapper<User2> userWrapper = objectWrappers.get(i);

            users.add(this.extractUserOrLoadFromDB(userWrapper, userId, redisKey));
        }

        return users;
    }

    @Override
    public Integer updateUser(User2 user) {
        // 自动生成 lastChanged 时间
        user.setLastChanged(LocalDateTime.now());
        int affectedRows = user2Mapper.update(user);
        if (affectedRows > 0) {
            this.cacheStore.remove(genKey(user.getUserId()));
            return affectedRows; // 更新成功
        } else {
            throw new OptimisticLockException("XXX", "修改的数据已被他人先行修改");
        }

    }

    @Override
    public void updateUserName(User2 user2) {
        user2.setName(user2.getName());
        user2Mapper.updateUserName(user2);
        this.cacheStore.remove(genKey(user2.getUserId()));
    }

    @Nullable
    private User2 extractUserOrLoadFromDB(final ObjectWrapper<User2> userWrapper, final Long userId, final String redisKey) {
        if (userWrapper.exists()) {
            return userWrapper.getObject();
        }

        if (userWrapper.notExists()) {
            return null;
        }

        final User2 user = user2Mapper.getUserById(userId).getObject();
        if (user != null) {
            this.cacheStore.setObject(redisKey, user, 1, TimeUnit.MINUTES);
        } else {
            this.cacheStore.setNotExists(redisKey);
        }

        return user;
    }
    //添加缓存操作然后进行判断先从缓存找数据，缓存没有再去找数据库
    //spring redis

    private String genKey(Long userId) {
        return String.join("_", "webRoot", "user", userId.toString());
    }

}

